from fastapi import APIRouter, status, HTTPException, Depends, Form
from fastapi.responses import JSONResponse
from passlib.context import CryptContext
from datetime import datetime, timedelta, timezone
from sqlalchemy.orm import Session
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from typing import Annotated
import jwt
from config import config
from databases import sessionlocal
from models import User
from schames import UserRegister
auth = APIRouter()


oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")

pwd_context = CryptContext(schemes=["bcrypt", "argon2"], deprecated="auto")
def get_db():
    db = sessionlocal()
    try:
        yield db
    finally:
        db.close()

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def create_token(data: dict):
    to_encode = data.copy()
    to_encode.update({"exp": datetime.now(timezone.utc) + timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES)})
    try:
        print(to_encode)
        token = jwt.encode(to_encode, config.SECRET_KEY, algorithm=config.ALGORITHM)
    except Exception as e:
        print(e)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="失败")
    return token

def construct_user_response(user: User) -> dict:
    """将用户对象转换为字典"""
    return {
        "username": user.username,
        "id": user.id,
        "email": user.email,
        "nickname": user.nickname
    }



def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)) -> dict:
    # 检查 token 是否为空
    if not token:
        raise HTTPException(status_code=401, detail="Unauthorized")

    try:
        # 尝试解码 JWT
        payload = jwt.decode(token, config.SECRET_KEY, algorithms=[config.ALGORITHM])
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token 已过期")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="无效的 Token")
    except Exception as e:
        raise HTTPException(status_code=401, detail=f"解码失败: {str(e)}")

    # 验证 payload 中的 sub 是否存在
    user_id = payload.get("id")
    if not user_id:
        raise HTTPException(status_code=401, detail="无效的 Token: 缺少用户 ID")

    # 查询数据库中的用户
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=401, detail="用户不存在")

    # 构造并返回用户信息
    return construct_user_response(user)

def authenticate_user(username: str, password: str, db: Session):
    if not username or not password:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="用户名或密码不能为空")
    user = db.query(User).filter(User.username == username).first()
    if not user or not verify_password(password, user.password):
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户名或密码错误")
    user = {"username": user.username, "id": user.id, "email": user.email, "nickname": user.nickname}
    return user

@auth.post("/login")
async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db = Depends(get_db)):
    if not form_data.username or not form_data.password:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="用户名或密码不能为空")
    user = authenticate_user(form_data.username, form_data.password, db)
    token = create_token({"id": user["id"]})
    return JSONResponse(status_code=status.HTTP_200_OK, content={"access_token": token, "token_type": "bearer"})

@auth.post("/register")
async def register(form_data: UserRegister = Form(), db: Session = Depends(get_db)):
    if not form_data.username or not form_data.password or not form_data.email or not form_data.nickname:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="用户名或密码不能为空")
    NewUser = User(
        username=form_data.username,
        password=pwd_context.hash(form_data.password),
        email=form_data.email,
        nickname=form_data.nickname
    )
    try:
        db.add(NewUser)
        db.commit()
        db.flush()
    except Exception as e:
        print(e)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="用户注册失败")
    return JSONResponse(status_code=status.HTTP_201_CREATED, content={"message": "用户注册成功"})
